import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('补间、物理模拟动画'),
        ),
        body:
            // CurveAnimation(), // 物理模拟动画
            //TweenAnimation(), // 补间动画
            HeartPage(),
      ),
    );
  }
}

// 非线性动画
// 物理动画，模拟物理行为，如弹性、阻尼、重力等，对Animation的封装
class CurveAnimation extends StatefulWidget {
  @override
  _CurveAnimationState createState() => _CurveAnimationState();
}

class _CurveAnimationState extends State<CurveAnimation>
    with SingleTickerProviderStateMixin {
  Animation<double> animation;
  AnimationController controller;
  AnimationStatus animationStatus;
  double animationValue;

  @override
  void initState() {
    super.initState();
    controller =
        AnimationController(duration: Duration(seconds: 2), vsync: this);
    // 非线性，描述动画过程，设置动画执行的速率(速度曲线)
    CurvedAnimation curveAnimation =
        CurvedAnimation(parent: controller, curve: Curves.bounceIn);
    animation = Tween<double>(begin: 0, end: 150).animate(curveAnimation)
      ..addListener(() {
        setState(() {
          animationValue = animation.value;
        });
      });
  }

  @override
  void dispose() {
    super.dispose();
    controller.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      width: double.infinity,
      height: double.infinity,
      child: Column(
        children: [
          RaisedButton(
            onPressed: () {
              controller.reset();
              controller.forward();
            },
            child: Text('放大'),
          ),
          Container(
            child: FlutterLogo(),
            width: animation.value,
            height: animation.value,
          )
        ],
      ),
    );
  }
}

// 线性动画
class TweenAnimation extends StatefulWidget {
  @override
  _TweenAnimationState createState() => _TweenAnimationState();
}

class _TweenAnimationState extends State<TweenAnimation>
    with SingleTickerProviderStateMixin {
  // 用于生成动画的值，得知动画的状态(开始、停止、正在进行、处于相反状态)，但是无法得知动画的具象和渲染无关
  Animation<double> animation;

  // 继承Animation，管理Animation
  AnimationController animationController;

  // forward、completed、reverse、dismissed
  AnimationStatus animationStatus;
  double animationValue;

  @override
  void initState() {
    super.initState();
    // vsync垂直同步，限制垂直同步区域在执行动画的区域内，避免资源消耗
    //vsync时钟信号，转换T输出，控制动画进度、状态，最简单的方式，就是直接继承 SingleTickerProviderStateMixin
    animationController =
        AnimationController(duration: const Duration(seconds: 1), vsync: this);
    // Tween:设置动画执行的value范围，value通常在0~1，如果要指定其他值就需要使用Tween
    animation = Tween<double>(begin: 0, end: 150).animate(animationController)
      ..addListener(() {
        setState(() {
          animationValue = animation.value;
        });
      })
      ..addStatusListener((status) {
        setState(() {
          animationStatus = status;
        });
      });
  }

  @override
  void dispose() {
    super.dispose();
    // 释放资源
    animationController.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      width: double.infinity,
      height: double.infinity,
      child: Column(
        children: [
          RaisedButton(
            onPressed: () {
              // 让执行动画的控制回到原处
              animationController.reset();
              // 启动动画
              animationController.forward();
            },
            child: Text('放大'),
          ),
          Container(
            child: FlutterLogo(),
            width: animation.value,
            height: animation.value,
          )
        ],
      ),
    );
  }
}

// 心跳动画练习
class HeartPage extends StatefulWidget {
  @override
  _HeartPageState createState() => _HeartPageState();
}

class _HeartPageState extends State<HeartPage>
    with SingleTickerProviderStateMixin {
  AnimationController _animationController;
  CurvedAnimation _curvedAnimation;
  Animation _animation;

  @override
  void initState() {
    super.initState();
    _animationController =
        AnimationController(vsync: this, duration: Duration(seconds: 3));

    // 监听动画动画执行，刷新界面
    // 问题一：每次要更新UI都需要监听并写setState方法，麻烦
    // 问题二：调用setState会执行build方法，让非动画目标也重新刷新消耗资源
    /*_animationController.addListener(() {
      setState(() {});
    });*/

    _animationController.addStatusListener((status) {
      if (status == AnimationStatus.completed) {
        _animationController.reverse();
      } else if (status == AnimationStatus.dismissed) {
        _animationController.forward();
      }
    });

    _curvedAnimation =
        CurvedAnimation(parent: _animationController, curve: Curves.linear);

    _animation =
        Tween<double>(begin: 50.0, end: 100.0).animate(_curvedAnimation);
  }

  @override
  Widget build(BuildContext context) {
    return Center(
      child: GestureDetector(
        child:
            // 性能优化方案二 类似全局数据共享的Consumer
            AnimatedBuilder(
          animation: _animationController,
          builder: (ctx, child) {
            return Icon(
              Icons.favorite,
              color: Colors.red,
              size: _animation.value,
            );
          },
          child: Icon(
            Icons.favorite,
            color: Colors.red,
            size: _animation.value,
          ),
        )
        /* 性能优化方案一：IconAnimatedWidget(
            _animation)*/
        /* 原始写法性能低：Icon(
          Icons.favorite,
          color: Colors.red,
          size: _animation.value,
        )*/
        ,
        onTap: () {
          if (_animationController.isAnimating) {
            // 如果正在执行动画，点击后停止
            _animationController.stop();
          } else {
            // 不在执行动画，则启动动画
            if (_animationController.status == AnimationStatus.reverse) {
              _animationController.reverse();
            } else {
              _animationController.forward();
            }
          }
        },
      ),
    );
  }

  @override
  void dispose() {
    _animationController.dispose();
    super.dispose();
  }
}

// 性能优化方案一：避免每次执行Widget的build方法，刷新动画无关Widget
// 缺点一：每次都需要创建新类继承AnimatedWidget
// 缺点二：如果动画目标对象有子类，依然会调用子类的build方法，性能也不高
class IconAnimatedWidget extends AnimatedWidget {
  IconAnimatedWidget(Animation animation) : super(listenable: animation);

  @override
  Widget build(BuildContext context) {
    // listenable来自父类
    Animation anim = listenable;

    return Icon(
      Icons.favorite,
      color: Colors.red,
      size: anim.value,
    );
  }
}
